package com.vagavaga.tcpt;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;

public class MessagedTransportServer extends TransportServer {
    
    @Override
    protected Connection createConnection(Object attachment) {
        return new MessagedConnection(this, attachment);
    }
    
    protected static class MessagedConnection extends Connection {
        private ByteArrayBuffer internal = new ByteArrayBuffer();
        
        protected MessagedConnection(MessagedTransportServer server, Object attachment) {
            super(server, attachment);
        }

        @Override
        public void send(ByteBuffer buffer) throws IOException {
            ByteBuffer message = ByteBuffer.allocate(buffer.limit() + 4);
            message.putInt(buffer.limit());
            message.put(buffer);
            message.flip();
            super.send(message);
        }
        
        @Override
        public void close() throws IOException {
            internal.setLength(0);
            internal.trimToSize();
            super.close();
        }
        
        private ByteBuffer[] decodeMessages(ByteBuffer buffer) {
            internal.append(buffer);
            ArrayList<ByteBuffer> messages = new ArrayList<ByteBuffer>();
            
            int lensize = 4;
            
            while (true) {
                if (internal.length() > lensize) {
                    int len = internal.readInt(0);
                    
                    // do we have complete message ?
                    if (len + lensize <= internal.length()) {
                        byte[] msg = internal.getBytes(0, len + lensize);
                        internal.trimToSize(len + lensize);
                        messages.add(ByteBuffer.wrap(msg, lensize, len));
                        continue;
                    }
                }
                break;
            }
            return messages.toArray(new ByteBuffer[messages.size()]);
        }
    }

    @Override
    protected void fireDataReceived(IConnection conn, ByteBuffer buffer) {
        MessagedConnection mconn = (MessagedConnection) conn;
        ByteBuffer[] messages = mconn.decodeMessages(buffer);
        
        for (int i = 0, n = messages.length; i < n; i++) {
            super.fireDataReceived(conn, messages[i]);
        }
    }
}
